import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

class CarGame extends JFrame {
    // 游戏状态
    private final CardLayout cardLayout = new CardLayout();
    private final JPanel mainPanel = new JPanel(cardLayout);
    private GamePanel gamePanel;
    private MainMenuPanel menuPanel;
    private DifficultyMenu difficultyMenu;

    // 线程管理
    private ExecutorService enemyExecutor;
    private final AtomicBoolean gameRunning = new AtomicBoolean(false);
    private final AtomicBoolean isPaused = new AtomicBoolean(false);

    // 持久化数据
    private final Properties gameData = new Properties();
    private static final String DATA_FILE = "gamedata.properties";

    public CarGame() {
        loadGameData();
        initUI();
    }

    private void initUI() {
        setTitle("赛车躲避游戏");
        setSize(600, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        menuPanel = new MainMenuPanel(
                e -> showDifficultyMenu(),
                e -> exitGame()
        );

        difficultyMenu = new DifficultyMenu(this::startGame);

        mainPanel.add(menuPanel, "menu");
        mainPanel.add(difficultyMenu, "difficulty");
        add(mainPanel);

        startMenuAnimation();
        setVisible(true);
    }

    // 游戏核心逻辑
    private void startGame(int difficulty) {
        if (gameRunning.get()) return;

        int enemyCount = 3 + difficulty;
        int enemySpeed = 100 - difficulty*20;

        gameRunning.set(true);
        isPaused.set(false);
        enemyExecutor = Executors.newCachedThreadPool();

        Player player = new Player(300, 300);
        List<Enemy> enemies = new ArrayList<>();
        for (int i = 0; i < enemyCount; i++) {
            enemies.add(new Enemy(100 + i*150, 50, 1 + difficulty*0.5f));
        }

        gamePanel = new GamePanel(
                player,
                enemies,
                this::togglePause,
                this::returnToMenu,
                gameData.getProperty("highScore", "0"),
                this::gameOver
        );

        mainPanel.add(gamePanel, "game");
        cardLayout.show(mainPanel, "game");
        gamePanel.requestFocusInWindow();

        startEnemyMovement(enemies, player, enemySpeed);
    }

    private void startEnemyMovement(List<Enemy> enemies, Player player, int speed) {
        enemies.forEach(enemy ->
                enemyExecutor.execute(() -> {
                    while (gameRunning.get()) {
                        if (!isPaused.get()) {
                            enemy.moveTowards(player);
                            gamePanel.repaint();
                        }
                        try {
                            Thread.sleep(speed);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                })
        );
    }

    // 界面管理
    private void startMenuAnimation() {
        javax.swing.Timer timer = new javax.swing.Timer(50, e -> {
            menuPanel.animateButtons();
            menuPanel.repaint();
        });
        timer.start();
    }

    private void showDifficultyMenu() {
        cardLayout.show(mainPanel, "difficulty");
    }

    private void togglePause() {
        isPaused.set(!isPaused.get());
        gamePanel.setPauseText(isPaused.get() ? "游戏暂停 - 按P继续" : "");
    }

    private void returnToMenu() {
        gameRunning.set(false);
        if (enemyExecutor != null) {
            enemyExecutor.shutdownNow();
        }
        cardLayout.show(mainPanel, "menu");
        saveGameData();
    }

    // 数据管理
    private void loadGameData() {
        try (InputStream input = new FileInputStream(DATA_FILE)) {
            gameData.load(input);
        } catch (IOException e) {
            gameData.setProperty("highScore", "0");
        }
    }

    private void saveGameData() {
        try (OutputStream output = new FileOutputStream(DATA_FILE)) {
            gameData.store(output, "游戏存档");
        } catch (IOException e) {
            System.out.println("存档失败");
        }
    }

    private void gameOver(int score) {
        int currentHigh = Integer.parseInt(gameData.getProperty("highScore", "0"));
        if (score > currentHigh) {
            gameData.setProperty("highScore", String.valueOf(score));
            JOptionPane.showMessageDialog(this, "新纪录！得分：" + score);
        }
        saveGameData();
        returnToMenu();
    }

    private void exitGame() {
        saveGameData();
        System.exit(0);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(CarGame::new);
    }
}

// 界面组件
class MainMenuPanel extends JPanel {
    private final List<MenuButton> buttons = new ArrayList<>();
    private float animationPhase = 0;

    public MainMenuPanel(ActionListener startAction,
                         ActionListener exitAction) {
        setLayout(new GridBagLayout());
        setBackground(new Color(30, 30, 40));

        JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 0, 20));
        buttonPanel.setOpaque(false);

        buttons.add(new MenuButton("开始游戏", startAction));
        buttons.add(new MenuButton("退出游戏", exitAction));

        buttons.forEach(buttonPanel::add);
        add(buttonPanel);
    }

    void animateButtons() {
        animationPhase = (animationPhase + 0.1f) % (float)(Math.PI * 2);
        buttons.forEach(b -> b.updateAnimation(animationPhase));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        for (int i = 0; i < 50; i++) {
            float alpha = (float) (0.3 + Math.sin(animationPhase + i*0.2) * 0.2);
            g2d.setColor(new Color(100, 150, 200, (int)(alpha * 255)));
            int size = 20 + (int)(Math.sin(animationPhase + i) * 10);
            int x = (int)(getWidth() * Math.random());
            int y = (int)(getHeight() * Math.random());
            g2d.fillOval(x, y, size, size);
        }
    }
}

class MenuButton extends JButton {
    private float animationValue = 0;

    public MenuButton(String text, ActionListener listener) {
        super(text);
        setFont(new Font("微软雅黑", Font.BOLD, 24));
        setContentAreaFilled(false);
        setBorderPainted(false);
        setForeground(Color.WHITE);
        addActionListener(listener);

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                animationValue = 1;
            }

            @Override
            public void mouseExited(MouseEvent e) {
                animationValue = 0;
            }
        });
    }

    void updateAnimation(float phase) {
        animationValue = Math.max(0, Math.min(1,
                animationValue + (float)(Math.sin(phase) * 0.1)));
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        float scale = 1 + animationValue * 0.2f;
        g2d.translate(getWidth()/2, getHeight()/2);
        g2d.scale(scale, scale);
        g2d.translate(-getWidth()/2, -getHeight()/2);

        g2d.setColor(new Color(255, 140, 0, (int)(150 * animationValue)));
        g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 20, 20);

        super.paintComponent(g2d);
        g2d.dispose();
    }
}

class DifficultyMenu extends JPanel {
    public DifficultyMenu(DifficultySelectedListener listener) {
        setLayout(new GridBagLayout());
        setBackground(new Color(40, 40, 50));

        String[] levels = {"简单", "普通", "困难"};
        JPanel buttonPanel = new JPanel(new GridLayout(3, 1, 0, 20));
        buttonPanel.setOpaque(false);

        for (int i = 0; i < levels.length; i++) {
            final int difficultyLevel = i;
            JButton btn = new MenuButton(levels[i], e -> listener.onDifficultySelected(difficultyLevel));
            buttonPanel.add(btn);
        }

        add(buttonPanel);
    }
}

interface DifficultySelectedListener {
    void onDifficultySelected(int difficulty);
}

// 游戏组件
class GamePanel extends JPanel {
    private final Player player;
    private final List<Enemy> enemies;
    private String pauseText = "";
    private long startTime;
    private int score;
    private boolean gameOver = false;
    private final GameOverCallback gameOverCallback;

    public GamePanel(Player player,
                     List<Enemy> enemies,
                     Runnable pauseAction,
                     Runnable returnToMenu,
                     String highScore,
                     GameOverCallback callback) {
        this.player = player;
        this.enemies = enemies;
        this.gameOverCallback = callback;
        this.startTime = System.currentTimeMillis();

        setLayout(new BorderLayout());
        setBackground(Color.WHITE);

        JLabel highScoreLabel = new JLabel("最高记录: " + highScore);
        highScoreLabel.setFont(new Font("宋体", Font.BOLD, 16));
        add(highScoreLabel, BorderLayout.NORTH);

        addKeyListener(new GameKeyListener(pauseAction, returnToMenu));
        setFocusable(true);
    }

    public void setPauseText(String text) {
        pauseText = text;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        if (!gameOver) {
            checkCollisions();
            score = (int)((System.currentTimeMillis() - startTime) / 1000);

            // 绘制玩家车辆（蓝色）
            drawCar(g2d, player.getX(), player.getY(), Color.BLUE);

            // 绘制敌人车辆（红色）
            enemies.forEach(e ->
                    drawCar(g2d, e.getX(), e.getY(), Color.RED)
            );

            // 绘制分数
            g2d.setColor(Color.BLACK);
            g2d.drawString("当前得分: " + score, 10, 20);

            // 暂停文字
            if (!pauseText.isEmpty()) {
                g2d.setFont(new Font("黑体", Font.BOLD, 24));
                g2d.setColor(Color.ORANGE);
                int x = getWidth()/2 - g2d.getFontMetrics().stringWidth(pauseText)/2;
                g2d.drawString(pauseText, x, getHeight()/2);
            }
        } else {
            drawGameOver(g2d);
        }
    }

    private void drawCar(Graphics2D g2d, int x, int y, Color color) {
        // 绘制车辆主体
        g2d.setColor(color);
        int[] carX = {x, x+20, x+30, x+20};
        int[] carY = {y+10, y+10, y+20, y+30};
        g2d.fillPolygon(carX, carY, 4);

        // 绘制车窗
        g2d.setColor(new Color(200, 200, 255));
        g2d.fillRect(x+5, y+15, 10, 5);

        // 绘制车轮
        g2d.setColor(Color.BLACK);
        g2d.fillOval(x+2, y+25, 6, 6);
        g2d.fillOval(x+22, y+25, 6, 6);
    }

    private void checkCollisions() {
        final Rectangle playerBounds = new Rectangle(player.getX(), player.getY(), 30, 30);
        enemies.forEach(enemy -> {
            Rectangle enemyBounds = new Rectangle(enemy.getX(), enemy.getY(), 30, 30);
            if (playerBounds.intersects(enemyBounds)) {
                gameOver = true;
                gameOverCallback.onGameOver(score);
            }
        });
    }

    private void drawGameOver(Graphics2D g2d) {
        g2d.setColor(new Color(0, 0, 0, 150));
        g2d.fillRect(0, 0, getWidth(), getHeight());

        g2d.setColor(Color.WHITE);
        g2d.setFont(new Font("宋体", Font.BOLD, 36));
        String text = "游戏结束！得分：" + score;
        int x = (getWidth() - g2d.getFontMetrics().stringWidth(text)) / 2;
        int y = getHeight()/2;
        g2d.drawString(text, x, y);
    }

    private class GameKeyListener extends KeyAdapter {
        private final Runnable pauseAction;
        private final Runnable returnToMenu;

        public GameKeyListener(Runnable pauseAction, Runnable returnToMenu) {
            this.pauseAction = pauseAction;
            this.returnToMenu = returnToMenu;
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if (!gameOver) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_W -> player.move(0, -5);
                    case KeyEvent.VK_S -> player.move(0, 5);
                    case KeyEvent.VK_A -> player.move(-5, 0);
                    case KeyEvent.VK_D -> player.move(5, 0);
                    case KeyEvent.VK_P -> pauseAction.run();
                }
            }
            if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                returnToMenu.run();
            }
            repaint();
        }
    }
}

interface GameOverCallback {
    void onGameOver(int score);
}

class Player {
    private int x, y;

    public Player(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public synchronized void move(int dx, int dy) {
        x = Math.max(0, Math.min(560, x + dx));
        y = Math.max(0, Math.min(360, y + dy));
    }

    public synchronized int getX() { return x; }
    public synchronized int getY() { return y; }
}

class Enemy {
    private int x, y;
    private final float speed;

    public Enemy(int x, int y, float speed) {
        this.x = x;
        this.y = y;
        this.speed = speed;
    }

    public synchronized void moveTowards(Player player) {
        int dx = Integer.compare(player.getX(), x);
        int dy = Integer.compare(player.getY(), y);

        x += (int)(dx * speed);
        y += (int)(dy * speed);

        x = Math.max(0, Math.min(560, x));
        y = Math.max(0, Math.min(360, y));
    }

    public synchronized int getX() { return x; }
    public synchronized int getY() { return y; }
}